package tools

import (
	"context"
	"errors"
	"github.com/wonderivan/logger"
	"k8s-platform/service/k8s-ui"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

var Deployment deployment

type deployment struct{}

// 定义DeployCreate结构体，用于创建deployment需要的参数属性的定义
type DeployCreate struct {
	Name          string            `json:"name"`
	Namespace     string            `json:"namespace"`
	Replicas      int32             `json:"replicas"`
	Image         string            `json:"image"`
	Label         map[string]string `json:"label"`
	Cpu           string            `json:"cpu"`
	Memory        string            `json:"memory"`
	ContainerPort int32             `json:"container_port"`
	HealthCheck   bool              `json:"health_check"`
	HealthPath    string            `json:"health_path"`
	Pool          string            `form:"pool"`
}

// 定义DeploysNp类型，用于返回namespace中deployment的数量
type DeploysNp struct {
	Namespace string `json:"namespace"`
	DeployNum int    `json:"deployment_num"`
}

type DeploymentsResp struct {
	Items []appsv1.Deployment `json:"items"`
	Total int                 `json:"total"`
}

//func (p *deployment) GetDeployments(filterName, namespace string, limit, page int) (deploymentsResp *DeploymentsResp, err error) {
//	//获取deploymentList类型的deployment列表
//	deploymentList, err :=
//		K8s.K8s.ClientSet.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
//	if err != nil {
//		logger.Error(errors.New("获取Deployment列表失败, " + err.Error()))
//		return nil, errors.New("获取Deployment列表失败, " + err.Error())
//	}
//	//将deploymentList中的deployment列表(Items)，放进dataselector对象中，进行排序
//	selectableData := &DataSelector{
//		GenericDataList: p.toCells(deploymentList.Items),
//		DataSelect: &DataSelectQuery{
//			Filter: &FilterQuery{Name: filterName},
//			Paginate: &PaginateQuery{
//				Limit: limit,
//				Page:  page,
//			},
//		},
//	}
//	filtered := selectableData.Filter()
//	total := len(filtered.GenericDataList)
//	data := filtered.Sort().Paginate()
//	//将[]DataCell类型的deployment列表转为appsv1.deployment列表
//	deployments := p.fromCells(data.GenericDataList)
//	return &DeploymentsResp{
//		Items: deployments,
//		Total: total,
//	}, nil
//}

// 获取deployment详情
//func (d *deployment) GetDeploymentDetail(deploymentName string, namespace string) (deployment *appsv1.Deployment, err error) {
//
//	//通过colony 到数据库查询接口绑定名称
//	//通过接口调用实例参数
//	//k8sSql = &model.Createk8s{}
//	//tx := db.GORM.Where("colony = ?", colony).First(&k8sSql)
//	//if tx.Error != nil && tx.Error.Error() != "record not found" {
//	//	logger.Error("获取K8s_config_token数据k8s_name失败" + tx.Error.Error())
//	//	return nil, nil, errors.New("获取K8s_config_token数据k8s_name失败" + tx.Error.Error())
//	//}
//	////已经取到对应实例接口名称 k8sSql.Colony
//	//var colonyname = k8sSql.Colony
//
//	deployment, err =
//		K8s.ClientSet.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
//	if err != nil {
//		logger.Error(errors.New("获取Deployment详情失败, " + err.Error()))
//		return nil, errors.New("获取Deployment详情失败, " + err.Error())
//	}
//	return deployment, nil
//}
//

//// 设置deployment副本数
//func (*deployment) ScaleDeployment(deploymentName, namespace string, scaleNum int) (replicas int32, err error) {
//	//获取副本数对象
//	scale, err :=
//		K8s.ClientSet.AppsV1().Deployments(namespace).GetScale(context.TODO(), deploymentName, metav1.GetOptions{})
//	if err != nil {
//		logger.Error("获取Deployment副本数失败," + err.Error())
//		return 0, errors.New("获取Deployment副本数失败," + err.Error())
//	}
//	//修改副本数
//	scale.Spec.Replicas = int32(scaleNum)
//	//更新副本数
//	newScale, err := K8s.ClientSet.AppsV1().Deployments(namespace).UpdateScale(context.TODO(), deploymentName, scale, metav1.UpdateOptions{})
//	if err != nil {
//		logger.Error("更新Deployment副本数失败," + err.Error())
//		return 0, errors.New("更新Deployment副本数失败," + err.Error())
//	}
//
//	return newScale.Spec.Replicas, nil
//}

// 创建deployment,接收DeployCreate对象
func (d *deployment) CreateDeployment(data *DeployCreate) (err error) {

	//将data中的数据组装成appsv1.Deployment对象
	deployment := &appsv1.Deployment{
		//ObjectMeta中定义资源名、命名空间以及标签
		ObjectMeta: metav1.ObjectMeta{
			Name:      data.Name,
			Namespace: data.Namespace,
			Labels:    data.Label,
		},
		//Spec中定义副本数、选择器、以及pod属性
		Spec: appsv1.DeploymentSpec{
			Replicas: &data.Replicas,
			Selector: &metav1.LabelSelector{
				MatchLabels: data.Label,
			},
			Template: corev1.PodTemplateSpec{
				//定义pod名和标签
				ObjectMeta: metav1.ObjectMeta{
					Name:   data.Name,
					Labels: data.Label,
				},
				//定义容器名、镜像和端口
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:  data.Name,
							Image: data.Image,
							Ports: []corev1.ContainerPort{
								{
									Name:          "http",
									Protocol:      corev1.ProtocolTCP,
									ContainerPort: 80,
								},
							},

							// Existing Name, Image, and Ports definitions...
							//VolumeMounts: []corev1.VolumeMount{
							//	{
							//		Name:      "data",
							//		MountPath: "/path/to/mount",
							//	},
							//},
						},
					},
					//Volumes: []corev1.Volume{
					//	{
					//		Name: "data",
					//		VolumeSource: corev1.VolumeSource{
					//			PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
					//				ClaimName: "data",
					//			},
					//		},
					//	},
					//},
				},
			},
		},
		//Status定义资源的运行状态，这里由于是新建，传入空的appsv1.DeploymentStatus{}对象即可
		Status: appsv1.DeploymentStatus{},
	}
	//判断是否打开健康检查功能，若打开，则定义ReadinessProbe和LivenessProbe
	if data.HealthCheck {
		//设置第一个容器的ReadinessProbe，因为我们pod中只有一个容器，所以直接使用index 0即可
		//若pod中有多个容器，则这里需要使用for循环去定义了
		deployment.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{
			ProbeHandler: corev1.ProbeHandler{
				HTTPGet: &corev1.HTTPGetAction{
					Path: data.HealthPath,
					//intstr.IntOrString的作用是端口可以定义为整型，也可以定义为字符串
					//Type=0则表示表示该结构体实例内的数据为整型，转json时只使用IntVal的数据
					//Type=1则表示表示该结构体实例内的数据为字符串，转json时只使用StrVal的数据
					Port: intstr.IntOrString{
						Type:   0,
						IntVal: data.ContainerPort,
					},
				},
			},
			//初始化等待时间
			InitialDelaySeconds: 5,
			//超时时间
			TimeoutSeconds: 5,
			//执行间隔
			PeriodSeconds: 5,
		}
		deployment.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{
			ProbeHandler: corev1.ProbeHandler{
				HTTPGet: &corev1.HTTPGetAction{
					Path: data.HealthPath,
					Port: intstr.IntOrString{
						Type:   0,
						IntVal: data.ContainerPort,
					},
				},
			},
			InitialDelaySeconds: 15,
			TimeoutSeconds:      5,
			PeriodSeconds:       5,
		}
		//定义容器的limit和request资源
		deployment.Spec.Template.Spec.Containers[0].Resources.Limits =
			map[corev1.ResourceName]resource.Quantity{
				corev1.ResourceCPU:    resource.MustParse(data.Cpu),
				corev1.ResourceMemory: resource.MustParse(data.Memory),
			}
		deployment.Spec.Template.Spec.Containers[0].Resources.Requests =
			map[corev1.ResourceName]resource.Quantity{
				corev1.ResourceCPU:    resource.MustParse(data.Cpu),
				corev1.ResourceMemory: resource.MustParse(data.Memory),
			}
	}
	//调用sdk创建deployment
	_, err = k8s_ui.K8s.ClientSet.AppsV1().Deployments(data.Namespace).Create(context.TODO(),
		deployment, metav1.CreateOptions{})
	if err != nil {
		logger.Error(errors.New("创建Deployment失败, " + err.Error()))
		return errors.New("创建Deployment失败, " + err.Error())
	}

	return nil
}

//// 删除deployment
//func (d *deployment) DeleteDeployment(deploymentName, namespace string) (err error) {
//	err = K8s.ClientSet.AppsV1().Deployments(namespace).Delete(context.TODO(),
//		deploymentName, metav1.DeleteOptions{})
//	if err != nil {
//		logger.Error(errors.New("删除Deployment失败, " + err.Error()))
//		return errors.New("删除Deployment失败, " + err.Error())
//	}
//	return nil
//}
//
//// 重启deployment
//func (*deployment) RestartDeployment(deploymentName, namespace string) (err error) {
//	//此功能等同于一下kubectl命令
//	//kubectl deployment ${service} -p \
//	//'{"spec":{"template":{"spec":{"containers":[{"name":"'"${service}"'","env":
//	//[{"name":"RESTART_","value":"'$(date +%s)'"}]}]}}}}'
//
//	patchData := map[string]interface{}{
//		"spec": map[string]interface{}{
//			"template": map[string]interface{}{
//				"spec": map[string]interface{}{
//					"containers": []map[string]interface{}{
//						{"name": deploymentName,
//							"env": []map[string]string{{
//								"name":  "RESTART_",
//								"value": strconv.FormatInt(time.Now().Unix(), 10),
//							}},
//						},
//					},
//				},
//			},
//		},
//	}
//
//	//把patchData序列化成字节
//	patchBytes, err := json.Marshal(patchData)
//	if err != nil {
//		logger.Error("序列化失败," + err.Error())
//		return errors.New("序列化失败," + err.Error())
//	}
//	//更新deployment
//	_, err = K8s.ClientSet.AppsV1().Deployments(namespace).Patch(context.TODO(), deploymentName, "application/strategic-merge-patch+json", patchBytes, metav1.PatchOptions{})
//	if err != nil {
//		logger.Error("重启Deployment失败," + err.Error())
//		return errors.New("重启Deployment失败," + err.Error())
//	}
//
//	return nil
//}
//
//// 更新deployment
//func (d *deployment) UpdateDeployment(namespace, content string) (err error) {
//	var deploy = &appsv1.Deployment{}
//	err = json.Unmarshal([]byte(content), deploy)
//	if err != nil {
//		logger.Error(errors.New("反序列化失败, " + err.Error()))
//		return errors.New("反序列化失败, " + err.Error())
//	}
//	_, err = K8s.ClientSet.AppsV1().Deployments(namespace).Update(context.TODO(),
//		deploy, metav1.UpdateOptions{})
//	if err != nil {
//		logger.Error(errors.New("更新Deployment失败, " + err.Error()))
//		return errors.New("更新Deployment失败, " + err.Error())
//	}
//	return nil
//}
//
//// 获取每个namespace的deployment数量
//func (d *deployment) GetDeployNumPerNp() (deploysNps []*DeploysNp, err error) {
//	namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(),
//		metav1.ListOptions{})
//	if err != nil {
//		return nil, err
//	}
//	for _, namespace := range namespaceList.Items {
//		deploymentList, err :=
//			K8s.ClientSet.AppsV1().Deployments(namespace.Name).List(context.TODO(),
//				metav1.ListOptions{})
//		if err != nil {
//			return nil, err
//		}
//		deploysNp := &DeploysNp{
//			Namespace: namespace.Name,
//			DeployNum: len(deploymentList.Items),
//		}
//		deploysNps = append(deploysNps, deploysNp)
//	}
//	return deploysNps, nil
//}
//
//// toCells方法用于将pod类型转成DataCell类型
//func (*deployment) toCells(std []appsv1.Deployment) []DataCell {
//	cells := make([]DataCell, len(std))
//	for i := range std {
//		//std[i]原生pod类型 -> podCell -> DataCell
//		cells[i] = deploymentCell(std[i])
//	}
//	return cells
//}
//
//// fromCells方法用于将DataCell类型转成pod类型
//func (*deployment) fromCells(cells []DataCell) []appsv1.Deployment {
//	deployments := make([]appsv1.Deployment, len(cells))
//	for i := range cells {
//		//cells[i] DataCell接口类型 -> podCell -> 原生pod类型
//		deployments[i] = appsv1.Deployment(cells[i].(deploymentCell))
//	}
//	return deployments
//}
